#pragma once

#include "Net.hpp"

namespace zgwrpc
{

    class Callback
    {
        public:
        using ptr=std::shared_ptr<Callback>;
        virtual void OnMessage(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg)=0;//定义回调函数接口
    };
 
    template <typename T>
    class CallbackT:public Callback
    {
    public:
        using ptr=std::shared_ptr<CallbackT<T>>;
        using OnMessage_cb=std::function<void(const BaseConnection::ptr &conn, const std::shared_ptr<T> &msg)>;
        CallbackT(OnMessage_cb handler): _handler(handler) {}


        void OnMessage(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg)
        {
            auto type_msg=std::dynamic_pointer_cast<T>(msg);
            _handler(conn, type_msg);   
        }

    private:
        OnMessage_cb _handler;
    };

    // 构建一个任务派发类， 可以用于注册消息处理函数， 并根据消息类型进行派发
    class Dispatcher
    {
    public:
        using ptr = std::shared_ptr<Dispatcher>;
        template <typename T>
        void registerHandler(MType type, const typename CallbackT<T>::OnMessage_cb &callback)
        {
            std::unique_lock<std::mutex> lock(_mu);
            auto it=std::make_shared<CallbackT<T>>(callback);
            _handers.insert(std::make_pair(type, it));
        }

        void dispatch(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg)
        {
            unique_lock<mutex> lock(_mu);
            MType type = msg->mtype();
            
            auto it = _handers.find(type);
            if (it != _handers.end())
            {
                it->second->OnMessage(conn, msg);
                return;
            }
            
            conn->shutdown();
            LOG(LogLevel::ERROR) << "没有注册对应的方法";
        }

    private:
        //map<MType,<T>> _handers;
        map<MType,Callback::ptr> _handers;
        mutex _mu;
    };

    class DispatcherFactory
    {
    public:
        template <typename... Args>
        static Dispatcher::ptr create(Args &&...args)
        {
            return make_shared<Dispatcher>(forward<Args>(args)...);
        }
    };
}